package com.inco.cloud.auth.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.inco.cloud.auth.feign.service.FeignService;
import com.inco.cloud.common.entity.UserEntity;
import com.inco.cloud.common.util.SecuityUtils;
import com.inco.cloud.common.model.ReturnT;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.security.oauth2.provider.token.ConsumerTokenServices;
import org.springframework.stereotype.Controller;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@Api(tags="授权中心-用户控制器")
@RestController(value="com.inco.cloud.auth.controller.UserController")
@RequestMapping("user")
public class UserController {
    Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private Environment env;

    @Autowired
    private ConsumerTokenServices consumerTokenServices;

    @Autowired
    private TokenEndpoint tokenEndpoint;

    @Autowired
    private SecuityUtils secuityUtils;

    @ApiOperation("登录接口")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ReturnT queryLogin(@RequestBody Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = 
                new UsernamePasswordAuthenticationToken(parameters.get("client_id"), parameters.get("client_secret"), new ArrayList<>());
        ResponseEntity<OAuth2AccessToken> oAuth2AccessToken = null;
        Map map = new HashMap();
        ReturnT re = new ReturnT(map);
        oAuth2AccessToken = tokenEndpoint.postAccessToken(usernamePasswordAuthenticationToken, parameters);
        OAuth2AccessToken body = oAuth2AccessToken.getBody();
        map.put("tokenInfo",body);
        return re;
    }
    @ApiOperation("登出接口")
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    public ReturnT logout(HttpServletRequest request){
        Map map = new HashMap();
        ReturnT re = new ReturnT(map);
        String access_token = secuityUtils.getToken();
        if (consumerTokenServices.revokeToken(access_token)){
            re.setSuccess(true);
            re.setMsg("注销成功");
        }else {
            re.setSuccess(false);
            re.setMsg("注销失败");
        }
        return re;
    }
    /**
     * 返回用户信息
     * @return
     */
    @ResponseBody
    @RequestMapping("/me")
    public ReturnT me() {
        Map map = new HashMap();
        ReturnT re = new ReturnT(map);
        UserEntity userEntity = secuityUtils.getCurrentUser();
        map.put("userInfo",userEntity);
        return re;
    }
    /**
     * 返回用户信息
     * @return
     */
    @ResponseBody
    @RequestMapping("/appEdit")
    public ReturnT appEdit(@RequestBody Map<String, String> parameters) {
        Map map = new HashMap();
        ReturnT re = new ReturnT(map);
        System.out.println(parameters);
        return re;
    }
    @ResponseBody
    @RequestMapping("/server-port")
    public String serverPort() {
        System.out.println("==========="+env.getProperty("user.name"));
        return env.getProperty("server.port");
    }

    @ResponseBody
    @RequestMapping("/user-name")
    public String userName() {
        return env.getProperty("user.name");
    }

    /**
     * 限流
     * value
     * 资源名称，必需项，因为需要通过resource name找到对应的规则，这个是必须配置的。
     * blockHandler
     *
     * blockHandler 对应处理 BlockException 的函数名称，可选项。
     * blockHandler 函数访问范围需要是 public，返回类型需要与原方法相匹配，
     * 参数类型需要和原方法相匹配并且最后加一个额外的参数，类型为 BlockException。
     * blockHandlerClass
     *
     * blockHandler 函数默认需要和原方法在同一个类中，如果希望使用其他类的函数，
     * 则需要指定 blockHandlerClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。
     * fallback
     *
     * fallback 函数名称，可选项，用于在抛出异常的时候提供 fallback 处理逻辑。
     * fallback 函数可以针对所有类型的异常（除了 exceptionsToIgnore 里面排除掉的异常类型）进行处理。
     * fallbackClass
     *
     * fallbackClass的应用和blockHandlerClass类似，fallback 函数默认需要和原方法在同一个类中。
     * 若希望使用其他类的函数，则可以指定 fallbackClass 为对应的类的 Class 对象，注意对应的函数必需为 static 函数，否则无法解析。
     * defaultFallback（since 1.6.0）
     *
     * 如果没有配置defaultFallback方法，默认都会走到这里来。
     * 默认的 fallback 函数名称，可选项，通常用于通用的 fallback 逻辑。
     * 默认 fallback 函数可以针对所有类型的异常（除了 exceptionsToIgnore 里面排除掉的异常类型）进行处理。
     * 若同时配置了 fallback 和 defaultFallback，则只有 fallback 会生效。
     * exceptionsToIgnore（since 1.6.0）
     *
     * 用于指定哪些异常被排除掉，不会计入异常统计中，也不会进入 fallback 逻辑中，而是会原样抛出。
     */
    @SentinelResource(value = "resource-hello-sentinel",blockHandler="helloSentinel")
    @ResponseBody
    @RequestMapping("/hello-sentinel")
    public String helloSentinel() {
        return String.format("[%s] 请求地址为：hello-sentinel",env.getProperty("spring.application.name"));
    }
    public String helloSentinel(BlockException blockException){
        return String.format("[%s] 请求hello-sentinel被限流,触发限流规则="+blockException.getRule().getResource(),env.getProperty("spring.application.name"));
    }

    //注入远程调用服务
    @Autowired
    private FeignService feignService;

    @ResponseBody
    @RequestMapping("/query-server-port")
    public String queryServerPort() {
        return feignService.serverPort();
    }

}
